package com.hb.trade.server.project.proj.manager;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.annotation.TableField;
import com.hb.core.pojo.enums.CommonTypeEnum;
import com.hb.core.pojo.project.proj.entity.AbstractProject;
import com.hb.core.pojo.project.proj.enums.BidWayEnum;
import com.hb.trade.server.project.util.TradeBeanUtil;
import org.fzzn.core.util.Enums;
import org.fzzn.core.util.IdUtil;

import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.List;

import static cn.hutool.core.date.DatePattern.PURE_DATE_FORMAT;

/**
 * 项目业务逻辑层
 *
 * @author zhaojk
 */
public class AbstractProjectManager extends AbstractProject {

    /**
     * 获取项目实体对象
     * 并将projectJSON中的属性复制到实体类中
     * 优先返回项目中定义的DTO模型类
     * 如果未定义返回实体类
     *
     * @param projectJSON 项目信息对象
     * @param bidWay      项目类型枚举
     * @param <T>
     * @return 优先返回项目中定义的DTO模型类, 如果未定义返回实体类
     */
    public static <T extends AbstractProject> T getInstance(BidWayEnum bidWay, JSONObject projectJSON) {
        Class<? extends AbstractProject> clazz = bidWay.getDtoTargetClass();
        if (clazz == null) {
            clazz = bidWay.getTargetClass();
        }
        if (projectJSON == null) {
            return (T) ReflectUtil.newInstance(clazz);
        }
        T toBean = projectJSON.toBean((Type) clazz);
        // 单独处理一下地区的属性, 前端传了一个前端字段数组
        JSONArray districts = projectJSON.getJSONArray("districts");
        if (CollUtil.isNotEmpty(districts)) {
            toBean.setProvince(districts.getStr(0));
            toBean.setCity(districts.getStr(1));
            toBean.setArea(districts.getStr(2));
        }
        return toBean;
    }

    /**
     * 获取项目实体对象
     *
     * @param bidWay 项目类型枚举
     * @param <T>    项目子类类型
     * @return
     */
    public static <T extends AbstractProject> T getInstance(BidWayEnum bidWay) {
        if (bidWay == null) {
            throw new RuntimeException("获取项目实体对象, [bidWay]不能为null");
        }
        return getInstance(bidWay, null);
    }

    /**
     * 获取项目实体对象
     *
     * @return
     */
    public static AbstractProject getInstance() {
        return new AbstractProject();
    }

    /**
     * 获取指定项目类型实体中的字段列表
     * 可用于自定义原生sql时拼接查询语句
     *
     * @param bidWay 项目类型枚举
     * @return
     */
    public static List<String> getSelectFields(BidWayEnum bidWay, boolean underLine) {
        // 获取真实的项目类型实体类
        Class<? extends AbstractProject> entityClass = bidWay.getTargetClass();
        // 获取实体类中的属性
        Field[] fields = ReflectUtil.getFields(entityClass);
        List<String> selectFields = CollUtil.list(false);
        for (Field field : fields) {
            String fieldName = field.getName();
            if ("log".equals(fieldName)) {
                continue;
            }
            if ("serialVersionUID".equals(fieldName)) {
                continue;
            }
            if ("createTime".equals(fieldName)) {
                continue;
            }
            if ("updateTime".equals(fieldName)) {
                continue;
            }
            if ("signStartTime".equals(fieldName)) {
                continue;
            }
            if ("signEndTime".equals(fieldName)) {
                continue;
            }
            TableField annotation = field.getAnnotation(TableField.class);
            if (annotation != null) {
                // 表字段中不存在的过滤
                boolean exist = annotation.exist();
                if (!exist) {
                    continue;
                }
            }
            if (underLine) {
                selectFields.add(StrUtil.toUnderlineCase(fieldName));
            } else {
                selectFields.add(fieldName);
            }
        }
        return selectFields;
    }

    /**
     * 将父类转换成指定类型的项目子类
     *
     * @param <T>
     * @param bidWay 招标方式枚举
     * @return
     */
    public <T extends AbstractProject> T castTo(BidWayEnum bidWay) {
        Class<? extends AbstractProject> clazz = bidWay.getDtoTargetClass();
        return (T) castTo(clazz);
    }

    /**
     * 将父类转换成指定类型的项目子类
     *
     * @param <T>
     * @param code 项目类型对应的code值
     * @return
     */
    public <T extends AbstractProject> T castTo(int code) {
        BidWayEnum bidWay = Enums.of(BidWayEnum.class, code);
        if (bidWay == null) {
            return null;
        }
        return castTo(bidWay);
    }

    /**
     * 将父类转换成指定类型的项目子类
     *
     * @param <T>
     * @param clazz 子类类型
     * @return
     */
    public <T extends AbstractProject> T castTo(Class<T> clazz) {
        if (this.getClass() == clazz) {
            return (T) this;
        }
        return this.to(clazz);
    }

    /**
     * 获取当前对象中指定字段的值
     * 子类调用
     *
     * @param fieldName 实际类型中的字段名称
     * @return
     */
    public Object get(String fieldName) {
        if (StrUtil.isEmpty(fieldName)) {
            return null;
        }
        return ReflectUtil.getFieldValue(this, fieldName);
    }

    /**
     * 根据当前项目的属性生成一个项目编号
     * FIXME 应根据项目的属性来进行构建, 比如公开邀请, 项目类型, 项目地区, 项目名称等, 后期优化
     */
    public void genCode() {
        this.setProjectCode(PURE_DATE_FORMAT.format(DateUtil.date()) + IdUtil.getIdStr());
    }

    /**
     * 获取项目枚举类实例
     *
     * @return
     */
    public CommonTypeEnum getCommonTypeEnum() {
        Integer commonType = getCommonType();
        if (commonType == null) {
            return null;
        }
        return Enums.of(CommonTypeEnum.class, commonType);
    }

    /**
     * 新增或修改项目信息时的参数验证
     *
     * @param projectJSON 前端传递的项目信息
     * @return
     */
    public static String valid(JSONObject projectJSON) {
        Integer projectModule = projectJSON.getInt("projectModule");
        if (projectModule == null) {
            return "未知的项目模块";
        }
        BidWayEnum bidWay = TradeBeanUtil.parseTradeJson(projectJSON);
        if (bidWay == null) {
            return "未知的项目类型: bidWay: [" + projectJSON.getStr("bidWay") + "]";
        }
        return null;
    }

    /**
     * 自动生成一个项目编号
     *
     * @author zhaojk
     */
    public String genProjectCode() {
        String objectId = IdUtil.objectId();
        setProjectCode(objectId);
        return objectId;
    }
}
